-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--[[

]]--
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local assets =
{
    Asset("ANIM", "anim/swap_llmy_anchor.zip"),
    Asset( "IMAGE", "images/inventoryimages/loramia_weapon_laser_cannon.tex" ),
    Asset( "ATLAS", "images/inventoryimages/loramia_weapon_laser_cannon.xml" ),
    Asset( "IMAGE", "images/widgets/loramia_laser_cannon_hud.tex" ),
    Asset( "ATLAS", "images/widgets/loramia_laser_cannon_hud.xml" ),
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 参数表
    local LASER_CANNON_DAMAGE = TUNING["loramia.Config"].LASER_CANNON_DAMAGE or 200
    local HUNGER_COST = TUNING["loramia.Config"].LASER_CANNON_HUNGER_VALUE_COST or 150
    local RECHARGE_COST = TUNING["loramia.Config"].LASER_CANNON_RECHARGE_VALUE_COST or 5
    local BATTERY_COST = 100    --- 内置电源的时候，消耗的值
    local BATTERY_MAX = 1000     --- 内置电源的时候，最大值
    local OVERLOAD_COST = 1     --- 内置电源的时候，过载消耗的值
    local OVERLOAD_MAX = 100    --- 内置电源的时候，过载最大值
    local OVERLOAD_MULT = 10    --- 过载的时候10倍伤害
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- 
    local function onequip(inst, owner)
        owner.AnimState:OverrideSymbol("swap_object","swap_llmy_anchor","swap_llmy_anchor")
        owner.AnimState:Show("ARM_carry")
        owner.AnimState:Hide("ARM_normal")

        if owner.components.loramia_com_rpc_event then
            if inst.___indicator_display_tast then
                inst.___indicator_display_tast:Cancel()
            end
            inst.___indicator_display_tast = inst:DoPeriodicTask(0.5,function()
                owner.components.loramia_com_rpc_event:PushEvent("player_onequipped",{userid = owner.userid},inst)
            end)
        end
    end

    local function onunequip(inst, owner)
        owner.AnimState:ClearOverrideSymbol("swap_object")
        owner.AnimState:Hide("ARM_carry")
        owner.AnimState:Show("ARM_normal")
        if inst.___indicator_display_tast then
            inst.___indicator_display_tast:Cancel()
            inst.___indicator_display_tast = nil
        end
    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 施法消耗
    local function CheckCanCastSpell(inst,doer)
        if inst:IsPlayerUnlockedTalent(doer) and inst.Power and inst.Power:Battery_Get() >= BATTERY_COST then
            return true
        end
        if doer.replica.hunger:GetCurrent() < HUNGER_COST then
            return false
        end
        if doer.replica.loramia_com_recharge:GetCurrent() < RECHARGE_COST then
            return false
        end
        return true     
    end
    local function DoSpellCastCost(inst,doer)
        if inst:IsPlayerUnlockedTalent(doer) and inst.Power and inst.Power:Battery_Get() >= BATTERY_COST  then        
            inst.Power:Battery_DoDelta(-BATTERY_COST)

            --- 创建5s的灯光
            if inst.__light_fx then
                inst.__light_fx:Remove()
            end            
            local temp_fx = SpawnPrefab("weremoose_shock_fx")
            temp_fx.Transform:SetPosition(doer.Transform:GetWorldPosition())
            inst.__light_fx = doer:SpawnChild("minerhatlight")
            inst.__light_fx:DoTaskInTime(5,function()
                inst.__light_fx:Remove()
                inst.__light_fx = nil
                temp_fx:Remove()
            end)

            return
        end
        doer.components.hunger:DoDelta(-HUNGER_COST,true)
        doer.components.loramia_com_recharge:DoDelta(-RECHARGE_COST)
    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---创建 激光
    -- local function CreateLaser(player,pt,onhitfn)
    --     SpawnPrefab("loramia_spell_laser_custom_caster"):PushEvent("Set",{
    --         attacker = player,
    --         pt = pt,
    --         onhitfn = onhitfn,
    --     })
    -- end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 归一化坐标
    -- local function GetPointAtDistance(pt1,pt2,distance)
    --     return TUNING.LORAMIA_FN:GetPointAlongLineAtDistance(pt1,pt2,distance)
    -- end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---
    local function IsPlayerUnlockedTalent(inst,player)
        if player.replica.loramia_com_talent_tree then
            return player.replica.loramia_com_talent_tree:IsUnlocked("creation_synchronization")
        end
        return false
    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 创建netvars和能量库
    local function Install_Net_Vars(inst)
        inst.power_battery = net_uint(inst.GUID,"power_battery","power_data_update")
        inst.power_overload = net_uint(inst.GUID,"power_overload","power_data_update")

        inst.Power = {}
        function inst.Power:Battery_DoDelta(value)
            if TheWorld.ismastersim then
                inst.power_battery:set(inst.components.loramia_data:Add("battery",value,0,BATTERY_MAX))
            end
        end
        function inst.Power:Battery_Get()
            if TheWorld.ismastersim then
                self:Battery_DoDelta()
            end
            return inst.power_battery:value()            
        end
        function inst.Power:Battery_IsFull()
            return self:Battery_Get() >= BATTERY_MAX
        end
        function inst.Power:Overload_DoDelta(value)
            if TheWorld.ismastersim then
                inst.power_overload:set(inst.components.loramia_data:Add("overload",value,0,OVERLOAD_MAX))
            end
        end
        function inst.Power:Overload_Get()
            if TheWorld.ismastersim then
                self:Overload_DoDelta(0)
            end
            return inst.power_overload:value()            
        end
        function inst.Power:Overload_IsFull()
            return self:Overload_Get() >= OVERLOAD_MAX
        end
        if TheWorld.ismastersim then
            inst.components.loramia_data:AddOnLoadFn(function()
                inst.Power:Battery_DoDelta(0)
                inst.Power:Overload_DoDelta(0)
            end)
        end

    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 创建box
    local function display_laser_cannon_hud(inst,indicator)
        local fn = require("prefabs/02_items/05_laser_cannon_hud")
        if type(fn) == "function" then
            fn(inst,indicator)
        end
    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 指示器创建
    local function CreateIndicator(inst,_data)
        if inst._indicator and inst._indicator:IsValid() or ThePlayer == nil or TheInput == nil or ThePlayer.HUD == nil then
            return
        end        
        local indicator = SpawnPrefab("loramia_sfx_dotted_arrow_client")
        indicator.AnimState:SetAddColour(0, 1, 1, 0)
        indicator.AnimState:SetMultColour(0, 1, 1, 1)
        indicator.AnimState:SetBloomEffectHandle("shaders/anim.ksh")
        indicator:PushEvent("Set",{
            pt = Vector3(ThePlayer.Transform:GetWorldPosition())
        })
        inst._indicator = indicator
        --- 指示器2
        local fx = SpawnPrefab("reticule")
        fx.Transform:SetPosition(ThePlayer.Transform:GetWorldPosition())
        fx.AnimState:SetAddColour(0, 1, 1, 0)
        fx.AnimState:SetMultColour(0, 1, 1, 1)
        fx.AnimState:SetBloomEffectHandle("shaders/anim.ksh")

        --- 定时检查指示器
        indicator:DoPeriodicTask(0.3,function()
            local weapon = ThePlayer.replica.combat and ThePlayer.replica.combat:GetWeapon()
            if weapon ~= inst then
                indicator:Remove()
                fx:Remove()
            end
        end)
        --- 刷新器
        TheInput:Loramia_Add_Update_Modify_Fn(indicator,function()
            if indicator.SetRotation then
                local x,y,z = ThePlayer.Transform:GetWorldPosition()
                local mouse_pt = TheInput:GetWorldPosition()
                indicator.Transform:SetPosition(x,y,z)
                local angle = -math.deg(math.atan2(mouse_pt.z - z,mouse_pt.x - x))
                indicator:SetRotation(angle)
                fx.Transform:SetPosition(mouse_pt.x,0,mouse_pt.z)
            else
                indicator:Remove()
            end
        end)

        --- 打开界面
        display_laser_cannon_hud(inst,indicator)

    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 点、目标 通用施法组件
    local function spell_caster_setup(inst)
        inst:ListenForEvent("Loramia_OnEntityReplicated.loramia_com_point_and_target_spell_caster",function(inst,replica_com)
            replica_com:SetAllowCanCastOnImpassable(true) -- 可以右键海中释放
            replica_com:SetDistance(10) -- 释放距离
            replica_com:SetTestFn(function(inst,doer,target,pt,right_click)
                if not right_click then
                    return false
                end
                --------------------------------------------------------------------------------
                ---
                    if target == doer then
                        return false
                    end
                    if not CheckCanCastSpell(inst,doer) then
                        return false
                    end
                --------------------------------------------------------------------------------
                return true
            end)
            replica_com:SetText("laser_cannon",TUNING.LORAMIA_FN:GetStringsTable("loramia_weapon_laser_cannon","action_str") or "发射") -- 显示文本
            replica_com:SetSGAction("loramia_laser_cannon_shoot") -- 配置执行的sg
            -- replica_com:SetPreActionFn(function(inst,doer,target,pt)
            -- end)
        end)
        if TheWorld.ismastersim then
            local main_com = inst:AddComponent("loramia_com_point_and_target_spell_caster")
            main_com:SetSpellFn(function(inst,doer,target,pt)
                if not CheckCanCastSpell(inst,doer) then
                    return false
                end
                -- print("+++++",doer,target,pt)
                ------------------------------------------------------------------------------------------------------------------------------
                --- 坐标提取。不论右键的是 某物品或者地面，统一修正为坐标。
                    local ret_pt = nil
                    if target then
                        ret_pt = Vector3(target.Transform:GetWorldPosition())
                    elseif type(pt) == "table" and pt.x then
                        ret_pt = pt
                    end
                    if ret_pt == nil then
                        return false
                    end
                    
                -- ------------------------------------------------------------------------------------------------------------------------------
                -- --[[
                --      【笔记】由于使用的是天体BOSS的激光，算法上 目标坐标 和 玩家坐标，锁死在 4 距离，则是动画上最佳效果。
                --       需要一套算法，把 ret_pt 锁死在射线轴 上距离玩家 4 距离的坐标点上。
                --      ]]--
                --     -- local dis_sq = doer:GetDistanceSqToPoint(ret_pt.x,ret_pt.y,ret_pt.z)
                --     -- local dis = math.sqrt(dis_sq)
                --     -- print("dis",dis)
                --     ret_pt = GetPointAtDistance(Vector3(doer.Transform:GetWorldPosition()),ret_pt,4)
                -- -------------------------------------------------------------------------------------------------------------------------------
                -- DoSpellCastCost(inst,doer)
                -- local laser_on_hit_fn = function(target)
                --     if target.components.health and target.components.combat then
                --         target.components.combat:GetAttacked(doer, TUNING["loramia.Config"].LASER_CANNON_DAMAGE or 200, inst)
                --     end
                -- end
                -- CreateLaser(doer,ret_pt,laser_on_hit_fn)
                -- -------------------------------------------------------------------------------------------------------------------------------
                -- -------------------------------------------------------------------------------------------------------------------------------
                -----------------------------------------------------------------------
                ---  参数更新
                    local weapon = inst
                    local player_pt = Vector3(doer.Transform:GetWorldPosition())
                    local OFFSET_START_DISTANCE = 1
                    local MAX_DISTANCE = 15 + OFFSET_START_DISTANCE
                    local damage = LASER_CANNON_DAMAGE
                    if inst:IsPlayerUnlockedTalent(doer) and inst.Power and inst.Power:Overload_Get() >= OVERLOAD_COST then
                        damage = damage * OVERLOAD_MULT
                        inst.Power:Overload_DoDelta(-OVERLOAD_COST)
                    end
                -----------------------------------------------------------------------
                --- 归一化向量
                    local Normalized_Dir = (ret_pt - player_pt):Normalize()
                -----------------------------------------------------------------------
                --- 
                    local start_pt = player_pt + Normalized_Dir * OFFSET_START_DISTANCE
                    local end_pt = player_pt + Normalized_Dir * MAX_DISTANCE
                -----------------------------------------------------------------------
                --- 
                    local BOUNCE_MUST_TAGS = { "_combat" }
                    local BOUNCE_NO_TAGS = { "INLIMBO", "wall", "notarget", "player", "companion", "flight", "invisible", "noattack", "hiding" }
                    local hit_targets = {}
                    SpawnPrefab("loramia_spell_line_laser_beam"):PushEvent("Set",{
                        start_pt = start_pt,
                        end_pt = end_pt,
                        colour = {0,255,255},
                        delta_length = 1,
                        delay_frame = 0.4,
                        onhit_delay_frame = 3,
                        onhitfn = function(x,y,z)
                            local ents = TheSim:FindEntities(x, 0, z, 1.2, BOUNCE_MUST_TAGS, BOUNCE_NO_TAGS)
                            for i,tempInst in ipairs(ents) do
                                if tempInst and tempInst:IsValid() and not hit_targets[tempInst] 
                                    and tempInst.components.combat 
                                    and tempInst.components.health and not tempInst.components.health:IsDead()
                                then
                                    hit_targets[tempInst] = true
                                    -----------------------------------------------------------------------
                                    if not doer.components.loramia_com_talent_tree:IsUnlocked("beam_suppression") then
                                        --- 普通伤害
                                        weapon.spell_casting = true
                                        tempInst.components.combat:GetAttacked(doer,damage,weapon)
                                        weapon.spell_casting = false
                                    else
                                        --- 天赋解锁，真实伤害

                                        weapon.spell_casting = true
                                        if doer.components.loramia_com_real_damage then
                                            doer.components.loramia_com_real_damage:DoRealDamage(tempInst,damage)
                                        else
                                            local damage_1 = damage - 5
                                            local damage_2 = damage - damage_1
                                            tempInst.components.health:DoDelta(-damage_2)
                                            tempInst.components.combat:GetAttacked(doer,damage_1,weapon)
                                        end
                                        weapon.spell_casting = false
                                    end
                                    -----------------------------------------------------------------------
                                end
                            end
                        end,
                    })
                -----------------------------------------------------------------------
                --- 消耗
                    DoSpellCastCost(inst,doer)
                -----------------------------------------------------------------------
                -- -------------------------------------------------------------------------------------------------------------------------------
                return true
            end)
        end
    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- 物品接受
    local IsGem = {
        ["redgem"] = 50,
        ["orangegem"] = 50,
        ["yellowgem"] = 50,
        ["greengem"] = 50,
        ["bluegem"] = 50,
        ["purplegem"] = 50,
    }
    local function acceptable_install(inst)
        inst:ListenForEvent("Loramia_OnEntityReplicated.loramia_com_acceptable",function(inst,replica_com)
            replica_com:SetTestFn(function(inst,item,doer,right_click)
                if not inst:IsPlayerUnlockedTalent(doer) then
                    return false
                end
                if IsGem[item.prefab] ~= nil or item.prefab =="loramia_item_luminescent_crystal" then
                    return true
                end
                return false
            end)
            replica_com:SetSGAction("give")
            replica_com:SetText("loramia_weapon_laser_cannon",STRINGS.ACTIONS.ADDFUEL)
        end)
        if not TheWorld.ismastersim then
            return
        end
        inst:AddComponent("loramia_com_acceptable")
        inst.components.loramia_com_acceptable:SetOnAcceptFn(function(inst,item,doer)
            if IsGem[item.prefab] then
                item.components.stackable:Get():Remove()
                inst.Power:Overload_DoDelta(IsGem[item.prefab] or 50)
                return true
            elseif item.prefab == "loramia_item_luminescent_crystal" then
                local DELTA_PER_ITEM = 100
                -- item.components.stackable:Get():Remove()
                -- inst.Power:Battery_DoDelta(100)
                local stack_num = item.components.stackable:StackSize()
                if stack_num == 1 then
                    --- 单个添加
                    item:Remove()
                    inst.Power:Battery_DoDelta(DELTA_PER_ITEM)
                    return true
                else
                    --- 处理成组添加
                    local Current = inst.Power:Battery_Get()
                    local need_num = math.ceil((BATTERY_MAX - Current) / DELTA_PER_ITEM)
                    if need_num >= stack_num then
                        inst.Power:Battery_DoDelta(stack_num * DELTA_PER_ITEM)
                        item:Remove()
                    else
                        inst.Power:Battery_DoDelta(need_num * DELTA_PER_ITEM)
                        item.components.stackable:Get(need_num):Remove()
                    end
                    return true
                end

            end
            return false
        end)

    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- onhitother  普通攻击，以目标为中心，半径1.5 aoe
    local AOE_RADIUS = 1.5
    if TUNING.LORAMIA_DEBUGGING_MODE then
        AOE_RADIUS = 10
    end
    local function onhitother(inst, attacker, target)
        if inst.spell_casting then
            return
        end
        if inst.aoe_doing_flag then -- 上锁
            return
        end
        local x,y,z = target.Transform:GetWorldPosition()
        local musthavetags = {"_combat"}
        local canthavetags = {"companion","player", "brightmare", "playerghost", "INLIMBO", "DECOR", "FX"}
        local musthaveoneoftags = nil
        -- local ents = TheSim:FindEntities(x,y,z,AOE_RADIUS, musthavetags, canthavetags, musthaveoneoftags)
        -- local ret_aoe_targets = {}
        -- for k, temp_target in pairs(ents) do
        --     if temp_target and temp_target ~= target then                
        --         if temp_target.components.health and temp_target.components.combat then
        --             table.insert(ret_aoe_targets,temp_target)
        --         end
        --     end
        -- end
        inst.aoe_doing_flag = true
        attacker.components.combat:DoAreaAttack(target,AOE_RADIUS,inst,nil,nil,canthavetags)
        inst.aoe_doing_flag = false
    end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)
    MakeInventoryFloatable(inst, "small")

    inst.AnimState:SetBank("swap_llmy_anchor")
    inst.AnimState:SetBuild("swap_llmy_anchor")
    inst.AnimState:PlayAnimation("idle")

    inst:AddTag("weapon")
    inst:AddTag("tool")

    inst.entity:SetPristine()
    --------------------------------------------------------------------------------
    ---
        if TheWorld.ismastersim then
            inst:AddComponent("loramia_data")
        end
    --------------------------------------------------------------------------------
    ---
        spell_caster_setup(inst)
        Install_Net_Vars(inst)
        acceptable_install(inst)
        inst.IsPlayerUnlockedTalent = IsPlayerUnlockedTalent
    --------------------------------------------------------------------------------
    --- 
        if not TheNet:IsDedicated() then
            inst:ListenForEvent("player_onequipped",CreateIndicator)
        end
    --------------------------------------------------------------------------------
    if not TheWorld.ismastersim then
        return inst
    end

    --------------------------------------------------------------------------------
    -- 普通武器
        inst:AddComponent("weapon")
        inst.components.weapon:SetDamage(40)
        inst.components.weapon:SetRange(1.5)
        inst.components.weapon:SetOnAttack(onhitother)
    --------------------------------------------------------------------------------
    -- 可检查、物品图标
        inst:AddComponent("inspectable")
        inst:AddComponent("inventoryitem")
        -- inst.components.inventoryitem:ChangeImageName("cane")
        inst.components.inventoryitem.imagename = "loramia_weapon_laser_cannon"
        inst.components.inventoryitem.atlasname = "images/inventoryimages/loramia_weapon_laser_cannon.xml"
    --------------------------------------------------------------------------------
    --- 可穿戴
        inst:AddComponent("equippable")
        inst.components.equippable:SetOnEquip(onequip)
        inst.components.equippable:SetOnUnequip(onunequip)
        inst.components.equippable.restrictedtag = "loramia"
    --------------------------------------------------------------------------------
    -- 当锤子用
        inst:AddComponent("tool")
        inst.components.tool:SetAction(ACTIONS.HAMMER)
    --------------------------------------------------------------------------------
    MakeHauntableLaunch(inst)

    return inst
end

return Prefab("loramia_weapon_laser_cannon", fn, assets)
